import {Gender, GenderEnum} from '../common/common.js'
import {FilterCategory, FilterParameter, PageResult, DiscoverBook, DiscoverSource} from './model/discover.js'

class AbstractDiscoverCrawler {

    /**
     *
     * @param {DiscoverSource} discoverSource
     */
    constructor(discoverSource) {
        this.source = discoverSource;
    }

    /**
     *
     * @param {Gender} gender
     * @returns {Promise<Array<FilterCategory>>}
     */
    async filterCategoryList(gender) {
        throw new Error('Method "filterCategoryList()" must be implemented in a subclass.');
    }

    /**
     *
     * @param {Number} pageNum
     * @param {Gender} gender
     * @param {Array<FilterParameter>} filterParameterList
     * @returns {Promise<PageResult<DiscoverBook>>}
     */
    async bookPage(pageNum, gender, filterParameterList) {
        throw new Error('Method "bookPage()" must be implemented in a subclass.');
    }

    /**
     *
     * @param {Gender} gender
     * @returns {Promise<Array<String>>}
     */
    async hotKeywordList(gender) {
        throw new Error('Method "hotKeywordList()" must be implemented in a subclass.');
    }

}

class DiscoverCrawlerTest {

    /**
     *
     * @param {AbstractDiscoverCrawler} discoverCrawler
     * @param {Array<FilterCategory>|null} filterCategoryList
     * @param {Boolean} filterSelectLast 过滤条件选择最后一个
     */
    constructor(discoverCrawler, {filterCategoryList, filterSelectLast = false} = {}) {
        if (!discoverCrawler instanceof AbstractDiscoverCrawler) throw new Error('DiscoverCrawlerTest: 参数 "discoverCrawler" 是必填，并且为 "AbstractDiscoverCrawler" 的子类。');
        if (filterCategoryList && filterCategoryList instanceof Array) throw new Error('DiscoverCrawlerTest: 参数 "filterCategoryList" 必须为 Array|null')
        if (!filterSelectLast instanceof Boolean) throw new Error('DiscoverCrawlerTest: 参数 "filterSelectLast" 必须为 Boolean')
        this.discoverCrawler = discoverCrawler;
        this.filterCategoryList = filterCategoryList;
        this.filterSelectLast = filterSelectLast;
    }

    async run() {
        const source = this.discoverCrawler.source;
        if (source.enableDiscover) {
            await this.runDiscover(source.enableGenderFilter);
        }

        if (source.enableHotKeyword) {
            await this.runHotKeyword(source.enableGenderFilter);
        }
    }

    /**
     *
     * @param {Boolean} enableGenderFilter
     * @return {Promise<void>}
     */
    async runDiscover(enableGenderFilter) {

        /**
         *
         * @param {Gender} gender
         * @param {DiscoverCrawlerTest} _this
         * @return {Promise<void>}
         */
        async function runDiscoverByGender(gender, _this) {
            const filterCategoryList = await _this.discoverCrawler.filterCategoryList(gender);
            console.log(`${gender.name} 过滤列表`, JSON.stringify(filterCategoryList, null, 2));

            const pageResult = await _this.discoverCrawler.bookPage(1, gender, (_this.filterCategoryList ?? filterCategoryList).map((e) => e.defaultFilterParameter(_this.filterSelectLast)));

            console.log(`${gender.name} 发现列表`, JSON.stringify(pageResult, null, 2));
        }

        if (enableGenderFilter) {
            await runDiscoverByGender(GenderEnum.male, this);
            await runDiscoverByGender(GenderEnum.female, this);
        } else {
            await runDiscoverByGender(GenderEnum.male, this);
        }
    }

    async runHotKeyword(enableGenderFilter) {

        /**
         *
         * @param {Gender} gender
         * @param {DiscoverCrawlerTest} _this
         * @return {Promise<void>}
         */
        async function runHotKeywordByGender(gender, _this) {
            console.log(`${gender.name} 热搜列表`, await _this.discoverCrawler.hotKeywordList(gender));
        }

        if (enableGenderFilter) {
            await runHotKeywordByGender(GenderEnum.male, this);
            await runHotKeywordByGender(GenderEnum.female, this);
        } else {
            await runHotKeywordByGender(GenderEnum.male, this);
        }
    }
}

export {AbstractDiscoverCrawler, DiscoverCrawlerTest}